package orm

import (
	"context"
	"orm/internal/errs"
	"strings"
)

// Selectable 是一个标记接口
// 它代表查找的列，或者聚合函数等
// SELECT XX 部分
type Selectable interface {
	selectable()
}

type Selector[T any] struct {
	builder

	table    string
	where    []Predicate
	columns  []Selectable
	groups   []Column
	having   []Predicate
	orderbys []OrderBy
	offset   int
	limit    int
	db       *DB
}

func NewSelector[T any](db *DB) *Selector[T] {
	return &Selector[T]{
		builder: builder{
			sb:      strings.Builder{},
			model:   nil,
			args:    nil,
			dialect: db.dialect,
			quoter:  db.dialect.quoter(),
		},
		db: db,
	}
}

func (s *Selector[T]) Build() (*Query, error) {
	var err error
	s.model, err = s.db.r.Get(new(T))
	if err != nil {
		return nil, err
	}

	s.sb.WriteString("SELECT ")
	err = s.buildColumns()
	if err != nil {
		return nil, err
	}
	s.sb.WriteString(" FROM ")

	//怎么拿到表名
	if s.table == "" {
		//var t T
		//Type := reflect.TypeOf(t)
		s.sb.WriteByte('`')
		s.sb.WriteString(s.model.TableName)
		s.sb.WriteByte('`')
	} else {
		//sb.WriteByte('`')
		s.sb.WriteString(s.table)
		//sb.WriteByte('`')
	}

	// 构造 WHERE
	if len(s.where) > 0 {
		// 类似这种可有可无的部分，都要在前面加一个空格
		s.sb.WriteString(" WHERE ")
		p := s.where[0]
		for i := 1; i < len(s.where); i++ {
			p = p.And(s.where[i])
		}
		if err = s.buildExpression(p); err != nil {
			return nil, err
		}

	}

	if len(s.having) > 0 {
		s.sb.WriteString(" HAVING ")
		p := s.having[0]
		for i := 1; i < len(s.having); i++ {
			p = p.And(s.having[i])
		}
		if err = s.buildExpression(p); err != nil {
			return nil, err
		}
	}

	// 构造Group By
	if len(s.groups) > 0 {
		s.sb.WriteString(" GROUP BY ")
		for i, c := range s.groups {
			if i > 0 {
				s.sb.WriteString(",")
			}
			if err = s.buildColumn(c); err != nil {
				return nil, err
			}
		}

	}

	// 构造Order By
	if len(s.orderbys) > 0 {
		s.sb.WriteString(" ORDER BY ")
		for i := 0; i < len(s.orderbys); i++ {
			if i > 0 {
				s.sb.WriteString(",")
			}
			p := s.orderbys[i]
			if err = s.buildExpression(p); err != nil {
				return nil, err
			}
		}

	}

	if s.offset > 0 {
		s.sb.WriteString(" OFFSET ?")
		s.addArgs(s.offset)
	}

	if s.limit > 0 {
		s.sb.WriteString(" LIMIT ?")
		s.addArgs(s.limit)
	}

	s.sb.WriteByte(';')

	return &Query{
		SQL:  s.sb.String(),
		Args: s.args,
	}, nil
}

func (s *Selector[T]) buildExpression(expr Expression) error {
	switch exp := expr.(type) {
	// 因为Not左分支
	case nil:
	case Predicate:
		_, lp := exp.left.(Predicate)
		if lp {
			s.sb.WriteByte('(')
		}
		if err := s.buildExpression(exp.left); err != nil {
			return err
		}
		if lp {
			s.sb.WriteByte(')')
		}
		if exp.op != "" {
			s.sb.WriteString(" ")
			s.sb.WriteString(exp.op.String())
			s.sb.WriteString(" ")
		}

		_, ok := exp.right.(Predicate)
		if ok {
			s.sb.WriteByte('(')
		}

		if err := s.buildExpression(exp.right); err != nil {
			return err
		}
		if ok {
			s.sb.WriteByte(')')
		}
	case Column:
		// 这种写法很隐晦
		exp.alias = ""
		return s.buildColumn(exp)
	case value:
		s.sb.WriteString("?")
		s.addArg(exp.val)
	case RawExpr:
		s.sb.WriteByte('(')
		s.sb.WriteString(exp.raw)
		s.addArg(exp.args...)
		s.sb.WriteByte(')')
	case Aggregate:
		// 聚合函数
		s.sb.WriteString(exp.fn)
		s.sb.WriteByte('(')
		err := s.buildColumn(Column{name: exp.arg})
		if err != nil {
			return err
		}
		s.sb.WriteByte(')')
		// 聚合函数本身的别名
		if exp.alias != "" {
			s.sb.WriteString(" AS ")
			s.sb.WriteByte('`')
			s.sb.WriteString(exp.alias)
			s.sb.WriteByte('`')
		}
	case OrderBy:
		err := s.buildColumn(Column{name: exp.col})
		if err != nil {
			return err
		}
		s.sb.WriteByte(' ')
		s.sb.WriteString(exp.order)
	default:
		return errs.NewErrUnsupportedExpression(expr)
	}
	return nil
}

func (s *Selector[T]) buildColumns() error {
	if len(s.columns) == 0 {
		// 没有指定列
		s.sb.WriteString("*")
		return nil
	}
	for i, col := range s.columns {
		if i > 0 {
			s.sb.WriteString(",")
		}
		switch c := col.(type) {
		case Column:
			err := s.buildColumn(c)
			if err != nil {
				return err
			}
		case Aggregate:
			// 聚合函数
			s.sb.WriteString(c.fn)
			s.sb.WriteByte('(')
			err := s.buildColumn(Column{name: c.arg})
			if err != nil {
				return err
			}
			s.sb.WriteByte(')')
			// 聚合函数本身的别名
			if c.alias != "" {
				s.sb.WriteString(" AS ")
				s.sb.WriteByte('`')
				s.sb.WriteString(c.alias)
				s.sb.WriteByte('`')
			}
		case RawExpr:
			// 原生表达式
			s.sb.WriteString(c.raw)
			s.addArg(c.args...)
		}

	}

	return nil
}
func (s *Selector[T]) buildColumn(c Column) error {
	// 字段不对，或者说列不对
	fd, ok := s.model.FieldsMap[c.name]
	if !ok {
		return errs.NewErrUnknownField(c.name)
	}
	s.sb.WriteByte('`')

	s.sb.WriteString(fd.ColName)
	s.sb.WriteByte('`')

	if c.alias != "" {
		s.sb.WriteString(" AS ")
		s.sb.WriteByte('`')
		s.sb.WriteString(c.alias)
		s.sb.WriteByte('`')
	}
	return nil
}

func (s *Selector[T]) addArg(vals ...any) {
	if len(vals) == 0 {
		return
	}
	if s.args == nil {
		s.args = make([]any, 0, 4)
	}
	s.args = append(s.args, vals...)
}

func (s *Selector[T]) Select(cols ...Selectable) *Selector[T] {
	s.columns = cols
	return s
}

//func (s *Selector[T]) Select(cols ...string) *Selector[T] {
//	s.columns = cols
//	return s
//}

func (s *Selector[T]) From(table string) *Selector[T] {
	s.table = table
	return s
}

// ids :=[]int{1,2,3}
// s.Where("id in (?,?,?)", ids)  不对
// s.Where("id in (?,?,?)", ids...)
//func (s *Selector[T]) where(query string, args...any)  {
//
//}

func (s *Selector[T]) Where(pridicate ...Predicate) *Selector[T] {
	s.where = pridicate
	return s
}

func (s *Selector[T]) Having(pridicate ...Predicate) *Selector[T] {
	s.having = pridicate
	return s
}
func (s *Selector[T]) GroupBy(cols ...Column) *Selector[T] {
	s.groups = cols
	return s
}

func (s *Selector[T]) OrderBy(orderBys ...OrderBy) *Selector[T] {
	s.orderbys = orderBys
	return s
}

func (s *Selector[T]) Offset(offset int) *Selector[T] {
	s.offset = offset
	return s
}

func (s *Selector[T]) Limit(limit int) *Selector[T] {
	s.limit = limit
	return s
}

//func (s *Selector[T]) GetV1(ctx context.Context) (*T, error) {
//	q, err := s.Build()
//	if err != nil {
//		return nil, err
//	}
//
//	// 在这里，就是发起查询，并且处理结果集
//	db := s.db.db
//	rows, err := db.QueryContext(ctx, q.SQL, q.Args...)
//	// 查询失败
//	if err != nil {
//		return nil, err
//	}
//	if !rows.Next() {
//		// 你要确认有没有数据
//		return nil, errs.ErrNoRows
//	}
//	// 在这里，继续处理结果集
//	// 获取有哪些列
//	cs, err := rows.Columns()
//	if err != nil {
//		return nil, err
//	}
//	tp := new(T)
//	var vals []any
//	// 起始地址
//	address := reflect.ValueOf(tp).UnsafePointer()
//	for _, c := range cs {
//		// c 是列明
//		fd, ok := s.model.ColumnMap[c]
//		if !ok {
//			return nil, errs.NewErrUnknownColumn(c)
//		}
//		// 起始地址+偏移量
//		fdAddress := unsafe.Pointer(uintptr(address) + fd.Offset)
//		val := reflect.NewAt(fd.Type, fdAddress)
//		// 反射在特定的地址上，创建一个特定类型的实例
//		// 这里创建的实例是原本类型的指针类型
//		// 例如fd.Type = int, 那么val是*int
//		vals = append(vals, val.Interface())
//	}
//	err = rows.Scan(vals...)
//	return tp, nil
//}

func (s *Selector[T]) Get(ctx context.Context) (*T, error) {
	s.Limit(1)
	q, err := s.Build()
	if err != nil {
		return nil, err
	}

	// 在这里，就是发起查询，并且处理结果集
	db := s.db.db
	rows, err := db.QueryContext(ctx, q.SQL, q.Args...)
	// 查询失败
	if err != nil {
		return nil, err
	}
	if !rows.Next() {
		// 你要确认有没有数据
		return nil, errs.ErrNoRows
	}

	tp := new(T)
	val := s.db.creator(s.model, tp)
	err = val.SetColumns(rows)
	// 接口定义好之后，就两件事，一个是用新接口的方法改造上层，
	// 一个就是提供不同的实现
	return tp, nil
}

func (s *Selector[T]) GetMulti(ctx context.Context) ([]*T, error) {
	q, err := s.Build()
	if err != nil {
		return nil, err
	}

	// 在这里，就是发起查询，并且处理结果集
	db := s.db.db
	rows, err := db.QueryContext(ctx, q.SQL, q.Args)
	// 查询失败
	if err != nil {
		return nil, err
	}

	// 在这里，继续处理结果集
	res := make([]*T, 0)
	for rows.Next() {
		tp := new(T)
		val := s.db.creator(s.model, tp)
		err = val.SetColumns(rows)
		res = append(res, tp)
	}

	return res, err
}
